(*  :Title:	Discrete-Time Fourier Transforms *)

(*  :Authors:	Wally McClure, Brian Evans, James McClellan  *)

(*
    :Summary:	This file will compute the forward and inverse
		discrete-time Fourier Transform of a signal.
 *)

(*  :Context:	SignalProcessing`Digital`DTFT`     *)

(*  :PackageVersion:  2.7	*)

(*
    :Copyright:	Copyright 1989-1991 by Brian L. Evans
		Georgia Tech Research Corporation

	Permission to use, copy, modify, and distribute this software
	and its documentation for any purpose and without fee is
	hereby granted, provided that the above copyright notice
	appear in all copies and that both that copyright notice and
	this permission notice appear in supporting documentation,
	and that the name of the Georgia Tech Research Corporation,
	Georgia Tech, or Georgia Institute of Technology not be used
	in advertising or publicity pertaining to distribution of the
	software without specific, written prior permission.  Georgia
	Tech makes no representations about the suitability of this
	software for any purpose.  It is provided "as is" without
	express or implied warranty.
 *)

(*
    :History:	start			October 2, 1989
		made into package	April 18, 1990
		made into release	May 25, 1990
		debugged fully		September 6, 1990
 *)

(*  :Keywords:	discrete-time Fourier transform  *)

(*
    :Source:	{Discrete-Time Signal Processing} by A. V. Oppenheim and
		  Ronald W. Schafer.  Prentice Hall.  1989
 *)

(*
    :Warning:	If the input does not match any given transform, a nasty
		expression is returned. (But isn't this true for any
		invalid transform in the signal processing packages?)
 *)

(*  :Mathematica Version:  1.2 or 2.0  *)

(*  :Limitation:  *)

(*
    :Discussion:  This  file  implements the forward and inverse DTFT.
		  The DTFTransform rule base (DTFTRules) consists of 5
		  property rules, 2  structure  rules  (upsampling and
		  downsampling),  13 lookup rules (for those functions
		  which  have  a  DTFT  but  not a z-transform), and 5
		  strategies --   distribute polynomials, expand terms
		  in cosine, sine,  and  exponential functions,  and a
		  call to  the  forward  z-transform rule base (if all
		  else fails).  The only functions supporting the for-
		  ward DTFT which depend  on the implementation of the
		  z-transform are ZtoDTFT and DTFTtoZ.

		  The InvDTFTransform is similarly arranged, having 11
		  lookup  rules,  6  property  rules, and 6 strategies
		  (including  a  call  to the inverse z-transform rule
		  base).  Only one rule in  InvDTFTRules  is dependent
		  on  the  implementation  of  the inverse z-transform
		  rule base InvZTransform.

	MyDTFT[f, n, w] determines the discrete-time Fourier transform
	of f with respect to n, where w is the frequency variable.

	MyInvDTFT[f, w, n] determines the inverse discrete-time Fourier
	transform of f with respect to w, where n is a "time" variable.

	These transform pairs are valid with respect to the DTFT formulas:

	    n
	(-1)                 w
	-----  <----->  - ------ CPulse[2 Pi, w + Pi]
	  n               2 I Pi

              n
	          (-1)
	- 2 I Pi  -----  <----->  w CPulse[2 Pi, w + Pi]
	            n
 *)

(*
    :Functions:	DTFTransform
		InvDTFTransform
 *)



(*  B E G I N     P A C K A G E  *)

BeginPackage[ "SignalProcessing`Digital`DTFT`",
	      "SignalProcessing`Digital`DSupport`",
	      "SignalProcessing`Digital`InvZTransform`",
	      "SignalProcessing`Digital`ZTransform`",
	      "SignalProcessing`Digital`ZSupport`",
	      "SignalProcessing`Support`TransSupport`",
	      "SignalProcessing`Support`ROC`",
	      "SignalProcessing`Support`SigProc`",
	      "SignalProcessing`Support`SupCode`" ]


If [ TrueQ[ $VersionNumber >= 2.0 ],
     Off[ General::spell ];
     Off[ General::spell1 ] ];


(*  U S A G E     I N F O R M A T I O N  *)

DTFTData::usage =
	"DTFTData is a data-tag."

DTFTransform::usage =
	"DTFTransform[function, in variable(s), out variable(s), options] \
	returns the discrete-time Fourier transform of the input function. \
	Note that this transform may rely on the z-transform and the \
	substitution z = Exp[I w], which is not valid if the region of \
	convergence does not include the unit circle.  Also note that \
	only the first two arguments are required."

InvDTFTransform::usage =
	"InvDTFTransform[function, in variable(s), out variable(s), options] \
	return the inverse discrete-time Fourier transform (inverse DTFT) \
	of the input function. \
	The first two arguments are required. \
	By default, the inverse DTFT rule base will apply the definition \
	of the inverse DTFT when all other attempts to find the inverse \
	have failed."

(*  E N D     U S A G E     I N F O R M A T I O N  *)


Begin[ "`Private`" ]


(*  B E G I N     P A C K A G E  *)

(*  Global variables  *)
nList = {}
wList = {}
zList = {}
multidFlag = False

(*  displayFixUp  *)
displayFixUp[ fixUp_, op_ ] :=
	Append[ fixUp[op], TransformLookup -> Replace[TransformLookup, op] ]

(*  validvarQ-- Valid variable checker  *)
validvarQ[ x_Symbol ] := True
validvarQ[ x_List ] := Apply[And, Map[VariableQ, x]]
validvarQ[ x_ ] := False

(*  Generate a unique symbol with a Global context.  *)
unique[x_] :=
	Block [	{context, newsymbol},
		context = $Context;
		$Context = "Global`";
		newsymbol = Unique[x];
		$Context = context;
		newsymbol ]


(*  B E G I N     F O R W A R D     D T F T  *)

(*  Conversion from operator notation to function notation  *)
Unprotect[DTFT]
DTFT/: TheFunction [ DTFT[n_, w_][f_] ] := DTFTransform[f, n, w]
Protect[DTFT]

(*  Options for the DTFT  *)
DTFTransform/: Options[ DTFTransform ] :=
	displayFixUp[ fixUp, { Dialogue -> False } ~Join~ Options[ZTransform] ]

(*  Extension of TheFunction operator.  *)
DTFTData/: TheFunction [ DTFTData[ trans_, var_ ] ] := trans

(*  Magnitude/Phase plot of a DTFT object *)
mppoptions = {	Domain -> Continuous, DomainScale -> Linear,
		MagRangeScale -> Linear, PhaseRangeScale -> Degree,
		PlotRange -> All }

DTFTData/: MagPhasePlot[DTFTData[trans_, FVariables[w_Symbol]]] :=
	MagPhasePlot[ trans, {w, -Pi, Pi}, mppoptions ]

DTFTData/: MagPhasePlot[DTFTData[trans_, FVariables[{w1_Symbol, w2_Symbol}]]] :=
	MagPhasePlot[ trans, {w1, -Pi, Pi}, {w2, -Pi, Pi}, mppoptions ]

(*  Input a function and test to see if needs to be sent to	*)
(*  the multidimensional or one-dimensional Fourier transform.	*)
DTFTransform[ f_ ] :=
	Message[ Transform::novariables, "n (time)", GetVariables[f] ]

DTFTransform[ f_, n_ ] :=
	DTFTransform [ f, n, DummyVariables[Length[n], Global`w] ]

DTFTransform[ f_, n_, w_, options___ ] :=
	Message[ Transform::badvar, "discrete-time", DTFTransform, n ] /;
	! validvarQ[n]

DTFTransform[ f_, n_, w_, options___ ] :=
	Message[ Transform::badvar, "continuous-frequency", DTFTransform, w ] /;
	! validvarQ[w]

DTFTransform[ f1_, n_, w_, options___ ] :=
	Block [	{op, trans, vars, zvars},
		vars = If [ Length[n] != Length[w],
			    DummyVariables[Length[n], Global`w],
			    w ];
		zvars = DummyVariables[Length[n], z];

		nList = ToList[n];
		wList = ToList[vars];
		zList = ToList[zvars];

		op = ToList[options] ~Join~ Options[DTFTransform];
		multidFlag = ( Length[n] > 1 );
		trans = If [ multidFlag, 
			     multiDDTFT[f1, n, vars, zvars, op],
			     MyDTFT[f1, n, vars, zvars, op] ];

		If [ InformUserQ[op],
		     Scan[explain, trans, Infinity] ];

		DTFTData[ trans, FVariables[vars] ] ]

(* Multidimensional discrete-time Fourier transform *)
multiDDTFT[ f1_, nl_, wl_, zl_, oplist_ ]:= 
	Block [	{fun = f1, i, len, newop},
		len = Length[nl];
		newop = MultiDLookup[oplist, nl, wl];
		For [ i = 1, i <= len, i++,
		      fun = MyDTFT[fun, nl[[i]], wl[[i]], zl[[i]], newop] ];
		fun ]

(*  One-dimensional discrete-time Fourier transform  *)
MyDTFT[ x_, n_, w_, z_, oplist_ ] :=
	Block [ {newexpr = myDTFT[x, n, w, z, fixUp[oplist], initDTFTstate[]],
		 newdtftrules, newtrans, oldexpr = Null, ret, trace},

		(* generate the DTFT rules *)
		newdtftrules = TransformFixUp[ n, w, oplist, myDTFT, False,
					       DTFTransform, Null, Null ];
		DTFTRules = Join[ newdtftrules, OriginalDTFTRules ];

		(* determine the level of dialogue *)
		trace = SameQ[ Replace[Dialogue, oplist], All ];

		(* take the 1-D DTFT *)
		Off[ Power::infy ];
		While [ ! SameQ[newexpr, oldexpr], 
			If [ trace, Print[newexpr]; Print[ "which becomes" ] ];
			oldexpr = newexpr;
			newexpr = oldexpr /. ( myDTFT[a__] :>
				    Replace[ myDTFT[a], DTFTRules ] ) ];

		(* fix up the result *)
		newexpr = posttransform[oldexpr];
		While [ ! SameQ[newexpr, oldexpr], 
			If [ trace, Print[newexpr]; Print[ "which becomes" ] ];
			oldexpr = newexpr;
			newexpr = posttransform[oldexpr] ];

		(* convert any remaining z-transform artifacts  *)
		If [ ! FreeQ[{newexpr}, z],
		     newexpr = ( newexpr /. z -> Exp[I w] ) ];
		On[ Power::infy ];
		If [ trace, Print[newexpr] ];
		newtrans = If [ SameQ[Head[newexpr], ZTransData],
				TheFunction[newexpr],
				newexpr ];

		(* properly handle Periodic operators *)
		newtrans = newtrans /.
			Periodic[k_, e_][f_] :> Periodic[k, Expand[e]][f];
		newtrans = newtrans //.
			{ a_ Periodic[k_, w][f_] :> Periodic[k, w][a f],
			  Periodic[k_, w + w0_][f_] :> Periodic[k, w][f] /;
			    FreeQ[w0, w],		(* ignore shifts *)
			  Periodic[k_, a_ w + w0_.][f_] :>
			    Periodic[k / a, w][f] /;
			    FreeQ[w0, w] };		(* scale axis *)
		If [ trace, Print[ "which becomes" ]; Print[newexpr] ];

		(* simplify expression if requested *)
		If [ Replace[Simplify, op],
		     newtrans = SPSimplify[newtrans,
					   Dialogue -> trace,
					   Variables -> wList] ];

		newtrans ]

(*  Supporting Routines  *)

diagonalResamplingMatrixQ[mat_] := False  /; ! MatrixQ[mat]
diagonalResamplingMatrixQ[mat_] :=
	Block [ {cond = False, diag, dims, i},
		dims = Dimensions[mat];
		If [ dims[[1]] == dims[[2]],
		     diag = Table[ mat[[i,i]], { i, 1, dims[[1]] } ];
		     cond = Apply[And, Map[isinteger, diag] ] &&
			    SameQ[mat, DiagonalMatrix[diag]] ];
		cond ]

explain[ myDTFT[ x_, n_, rest__ ] ] :=
	Message[ Transform::incomplete,
		 "forward discrete-time Fourier transform", x, n ]

(*  fixUp --  removes redundancy and TransformLookup in options list  *)
fixUp[ op_ ] := { Definition -> Replace[Definition, op],
		  Dialogue -> Replace[Dialogue, op] }

isinteger[x_] := Implies[ NumberQ[x], IntegerQ[x] ]

isintegerMatrix[ x_ ] :=
	MatrixQ[x] && Apply[ SameQ, Dimensions[x] ] &&
	Apply[ And, Map[isinteger, Flatten[x]] ]

mDresampleCheck[Downsample, n_, nvars_, nList_, m_] :=
	mDresampleCheck[Upsample, n, nvars, nList, m]

mDresampleCheck[Upsample, n_, nvars_, nList_, l_] :=
	Block [	{cond},
		cond = SubsetQ[{n}, nvars, nList] && isintegerMatrix[l];
		If [ cond, Needs[ "SignalProcessing`Digital`MDDTFT`" ] ];
		cond ]

posttransform[x_] := ( x /. postrules )

postrules = {
	(*	Apply the definition	*)
	myDTFT[ x_, n_, w_, z_, options_, flag_ ] :>
		Block [ {def, summhead},
        		summhead = If [ TrueQ[$VersionNumber >= 2.0],
					Needs[ "Algebra`SymbolicSum`" ];
					Algebra`SymbolicSum,
					Needs[ "Algebra`GosperSum`" ];
					Algebra`GosperSum ];
			def = summhead[x Exp[I w n], {n, -Infinity, Infinity}];
			TransformDialogue[ Definition, options,
					   summhead, x, def ] ] /;
		Replace[Definition, options],

	derivative[x_, w_, 1] :>
		I D[ posttransform[x], w ],
	derivative[x_, w_, k_] :>
		I^k D[ posttransform[x], {w, k} ],
	downsample[x_, w_Symbol, m_Integer] :>
		Block [ {k, newx},
			newx = posttransform[x] /. w -> ((w + 2 Pi k) / m);
			Sum[newx, {k, 0, Abs[m]-1}] / Abs[m] ],
	downsample[x_, w_Symbol, m_] :>
		Block [ {k, newx},
			k = Unique["k"];
			newx = posttransform[x] /. w -> ((w + 2 Pi k) / m);
			Summation[k, 0, Abs[m]-1, 1][newx] / Abs[m] ],
	DTFTtoZ[x_] :>
		Transform[ x, 0, Infinity ],
	DTFTtoZ[x_, w_, z_] :>
		Transform[ substituteforw[x, w, -I Log[z]], 0, Infinity ],
	myDTFT[ZTransData[x_, zrest__], rest__] :>
		x,
	substituteforw[x_, w_Symbol, w0_, opstr_, op_] :>
		op[substituteforw[x, w, w - w0], substituteforw[x, w, w + w0]],
	substituteforw[x_, w_Symbol, -w] :>
		If [ Count[{x}, f_[p___][a___], Infinity] > 0,
		     Rev[w][posttransform[x]],          (* operators present *)
		     posttransform[x] /. w -> -w ] ,    (* no operators *)
	substituteforw[x_, w_Symbol, wnew_] :>
		( posttransform[x] /. w -> wnew ),
	upsamplemD[x_, {}, w_List, l_?MatrixQ] :>
		( posttransform[x] /. ReplaceWith[w, l . w] ),
	upsamplemD[x_, nlist_, w_, l_] :>
		upsamplemD[ posttransform[x], nlist, w, l ],
	downsamplemD[x_, {}, w_, m_?MatrixQ] :>
		postdownsamplemD[x, w, m],
	downsamplemD[x_, nlist_, w_, m_] :>
		downsamplemD[ posttransform[x], nlist, w, m ]
}

ZtoDTFT[ SignalProcessing`Digital`ZTransform`Private`forwardz[x_, zrest__], n_, w_, z_, rest__ ] :=
	DTFTtoZ[ myDTFT[x, n, w, z, rest], w, z ]
ZtoDTFT[ x_, n_, w_, z_, rest__ ] := x


(*  Printed forms of supported routines for Dialogue -> All option  *)

Format[ myDTFT[ x_, n_, w_, z_, options_, flag_ ] ] :=
	SequenceForm[ ColumnForm[{"DTFT",
				  "     " ~StringJoin~ ToString[n]}],
		      { x } ]

Format[ derivative[x_, w_Symbol, k_] ] := 
	SequenceForm[ ColumnForm[{"D" Superscript[k],
				  "  " ~StringJoin~ ToString[w]}],
		      { x } ]

Format[	substituteforw[x_, w_, wnew_] ] :=
	SequenceForm[ {x}, Subscript[w -> wnew] ]

Format[	substituteforw[x_, w_, w0_, opstr_, op_] ] :=
	SequenceForm[ {x}, Subscript[w -> w - w0], opstr,
		      {x}, Subscript[w -> w + w0] ]

Format[	DTFTtoZ[x_, w_, z_] ] :=
	SequenceForm[ {x}, Subscript[w -> -I Log[z]] ]

Format[ downsample[x_, w_, m_] ] :=
	SequenceForm[ {x}, Subscript[w -> ((w + 2 Pi "k")/m)] ]

Format[ downsamplemD[x_, n_, w_, m_] ] :=
	SequenceForm[ {x}, Subscript["aliased by " m] ]

Format[ upsamplemD[x_, n_, w_, m_] ] :=
	SequenceForm[ {x}, Subscript[w -> m . w] ]


Format[ z ] := "z"


(*  S T A T E  *)

initDTFTstate[] := True
nullDTFTstate[] := False


(*  B E G I N     D T F T     R U L E     B A S E  *)


DTFTRules = {}


OriginalDTFTRules = {


(*  A.	Lookup rules		*)
(*	1.  Pulse		*)
myDTFT[ Pulse[L_, n_ + n0_.], n_, w_, z_, options_, flag_ ] :>
	Periodic[2 Pi, w][Exp[I w n0] Exp[- I w (L - 1) / 2] Dirichlet[L, w]] /;
	FreeQ[{L, n0}, n],

myDTFT[ A_. Step[n_ + n0_.] - A_. Step[n_ + n1_.] + x_, n_, w_, z_, options_, flag_ ] :>
	myDTFT[ A Pulse[Abs[n1 - n0], n + Min[-n0, -n1]],
		n, w, z, options, flag ] +
	myDTFT[ x, n, w, z, options, flag ] /;
	FreeQ[{n0, n1}, n],

(*	2.  Step		*)
myDTFT[ Step[n_ + n0_.], n_, w_, z_, options_, flag_ ] :> 
	Block [	{l = unique["l"]},
		Exp[I w n0] / ( 1 - Exp[-I w] ) + 
		  Pi Exp[I w n0] Summation[l, -Infinity, Infinity, 1]
				       [Delta[w + 2 Pi l]] ] /;
	FreeQ[n0, n],

(*	3.  Summation forms	*)
myDTFT[ Summation[k_, -Infinity, Infinity, 1][x_],
		n_, w_, z_, options_, flag_ ] :>
	Summation[k,-Infinity,Infinity,1][
		myDTFT[x, n, w, z, options, flag] ] /;
	FreeQ[k, n],

myDTFT[ Summation[k_, 0, L_, 1][a_. Exp[I m_ Pi k_ n_]],
		n_, w_, z_, options_, flag_ ] :>
	2 Pi Summation[k, -Infinity, Infinity,1][a Delta[w - 2 Pi k/(L+1)]] /;
	FreeQ[{a, k, L}, n] && SameQ[m, 2/(L+1)],

(*	4.  Infinite extent cosine	*)
myDTFT[ Cos[w0_. n_ + b_.], n_, w_, z_, options_, flag_ ] :> 
	Block [	{l = unique["l"]},
		Pi Summation[l,-Infinity,Infinity,1]
			    [Exp[I b w / w0] Delta[w - w0 + 2 Pi l] +
			     Exp[- I b w / w0] Delta[w + w0 + 2 Pi l]] ] /;
	FreeQ[{b, w0}, n],

(*	5.  Infinite extent sine	*)
myDTFT[ Sin[w0_. n_ + b_.], n_, w_, z_, options_, flag_ ] :> 
	Block [	{l = unique["l"]},
		Pi Summation[l,-Infinity,Infinity,1]
			    [- I Exp[I b w / w0] Delta[w - w0 + 2 Pi l] +
			     I Exp[I b w / w0] Delta[w + w0 + 2 Pi l]] ] /;
	FreeQ[{b, w0}, n],

(*	6.  Constant function		*)
myDTFT[ 1, n_, w_, z_, options_, flag_ ] :> 
	Block [	{l = unique["l"]},
		2 Pi Summation[l,-Infinity,Infinity,1][Delta[w + 2 Pi l]] ],

(*	7.  Sinc and other 1/n		*)
myDTFT[ (-1)^(n_ + a_.) / ( n_ - 1 ), n_, w_, z_, options_, flag_ ] :>
	Periodic[2 Pi, w][ (-1)^a w Exp[- I w] CPulse[2 Pi, w + Pi] ] /;
	FreeQ[a, n],

myDTFT[ 1/n_, n_, w_, z_, options_, flag_ ] :>
	Periodic[2 Pi, w][ - 2 Pi I CStep[w] ],

myDTFT[ Sinc[a_. n_ + b_.], n_, w_, z_, options_, flag_ ] :> 
	Periodic[2 Pi, w][ Exp[I b/a] Pi CPulse[2 Abs[a], w + Abs[a]] /
			   Abs[a] ] /;
	FreeQ[{a,b}, n],

myDTFT[ (Sinc[a_. n_ + b_.])^2, n_, w_, z_, options_, flag_ ] :> 
	Periodic[2 Pi, w][ Exp[I b / a] (Pi / a)^2 ( Unit[-2][w + 2 a] -
			   2 Unit[-2][w] + Unit[-2][w - 2 a] ) ] /;
	FreeQ[{a,b}, n],


(*  B.	Properties		*)
(*	1.  Multiplication by constant  *)
myDTFT[ a_ x_, n_, w_, z_, options_, flag_ ] :>
	a myDTFT[x, n, w, z, options, flag] /;
	FreeQ[a, n],

(*	2.  Additivity property	*)
myDTFT[ x_ + y_, n_, w_, z_, options_, flag_ ] :> 
	myDTFT[x, n, w, z, options, flag] + myDTFT[y, n, w, z, options, flag],

(*	3.  Multiplication by n	*)
myDTFT[ n_^a_. b_, n_, w_, z_, options_, flag_ ] :>
	Block [ {dialogue},
                dialogue = SameQ[ Replace[Dialogue, options], All ];
		Assuming[ a > 0, dialogue ];
		If [ dialogue, Print[ "where ", a, " is an integer" ] ];
		derivative[myDTFT[b, n, w, z, options, flag], w, a] ] /;
	FreeQ[a,n] && Implies[ NumberQ[a], IntegerQ[a] && a > 0 ],

(*	4.  Delay by m		*)
myDTFT[ f_. Step[n_ + m_], n_, w_, z_, options_, flag_ ] :>
	Exp[I m w] myDTFT[(f /. n->(n - m)) Step[n], n, w, z, options, flag] /;
	FreeQ[m, n],

(*	5.  Expand shifted sinusoids	*)
myDTFT[ Cos[a_. n_ + b_] x_., n_, w_, z_, options_, flag_ ] :> 
	myDTFT[ Cos[b] Cos[a n] x - Sin[b] Sin[a n] x,
		n, w, z, options, flag ] /;
	FreeQ[{a, b}, n],

myDTFT[ Sin[a_. n_ + b_] x_., n_, w_, z_, options_, flag_ ] :> 
	myDTFT[ Sin[b] Cos[a n] x + Cos[b] Sin[a n] x,
		n, w, z, options, flag ] /;
	FreeQ[{a, b}, n],

(*	6.  Multiplication by complex exponential	*)
myDTFT[ a_. Exp[Complex[0, w0_] w1_. n_ + b_.], n_, w_, z_, options_, flag_ ] :>
	Exp[b] substituteforw[ myDTFT[a, n, w, z, options, flag],
			       w, w - w0 w1 ] /;
	FreeQ[{b, w0, w1}, n],

myDTFT[ a_. Cos[w0_. n_], n_, w_, z_, options_, flag_ ] :>
	substituteforw[ myDTFT[a, n, w, z, options, flag] / 2,
			w, w0, "+", Plus ] /;
	FreeQ[w0, n],

myDTFT[ a_. Sin[w0_. n_], n_, w_, z_, options_, flag_ ] :>
	substituteforw[ -I/2 myDTFT[a, n, w, z, options, flag],
			w, w1, "-", Subtract ] /;
	FreeQ[w0, n],

(*  C.	Structures		*)
(*      -.  An operator independent of n---  take transform of f    *)
myDTFT[ operator_[params__][f_], n_, w_, z_, options_, flag_ ] :>
	operator[params][ myDTFT[f, n, w, z, options, flag] ] /;
	FreeQ[{params}, n],

(*	1.  Upsampling		*)
myDTFT[ Upsample[l_, n_] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	substituteforw[ myDTFT[x, n, w, z, options, flag], w, l w],

myDTFT[ Upsample[l_, nvars_List] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	Block [	{dim, expr, i},
		dim = Length[nvars];
		expr = x;
		For [ i = 1, i <= dim, i++,
		      expr = Upsample[ l[[i,i]], nvars[[i]] ][expr] ];
		myDTFT[ expr, n, w, z, options, flag ] ] /;
	MemberQ[nvars, n] && diagonalResamplingMatrixQ[l],

myDTFT[ Upsample[l_, nvars_List] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	upsampleSetUp[l, nvars, x, n, w, z, options, flag ] /;
	mDresampleCheck[Upsample, n, nvars, nList, l],

myDTFT[ upsamplemD[ x_, nlist_, wlist_, l_], n_, w_, z_, options_, flag_ ] :>
	upsamplemD[ myDTFT[x, n, w, z, options, flag ],
		    If [ MemberQ[nlist, n], Complement[nlist, {n}], nlist ],
		    wlist, l ],

(*	2.  Downsampling	*)
myDTFT[ Downsample[m_, n_] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	downsample[ myDTFT[x, n, w, z, options, flag], w, m ],

myDTFT[ Downsample[m_, nvars_List] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	Block [	{dim, expr, i},
		dim = Length[nvars];
		expr = x;
		For [ i = 1, i <= dim, i++,
		      expr = Downsample[ m[[i,i]], nvars[[i]] ][expr] ];
		myDTFT[expr, n, w, z, options, flag] ] /;
	MemberQ[nvars, n] && diagonalResamplingMatrixQ[m],

myDTFT[ Downsample[m_, nvars_List] [ x_ ], n_, w_, z_, options_, flag_ ] :>
	downsampleSetUp[m, nvars, x, n, w, z, options, flag ] /;
	mDresampleCheck[Downsample, n, nvars, nList, m],

myDTFT[ downsamplemD[ x_, nlist_, wlist_, m_], n_, w_, z_, options_, flag_ ] :>
	downsamplemD[ myDTFT[x, n, w, z, options, flag ],
		      If [ MemberQ[nlist, n], Complement[nlist, {n}], nlist ],
		      wlist, m ],

(*  D.	Strategies		*)
(*	1.  Multiply out terms in cosine, sin, and exponential functions.  *)
myDTFT[ Exp[a_] x_., n_, w_, z_, options_, flag_ ] :>
	myDTFT[ Exp[Expand[a]] x, n, w, options, flag ] /;
	! SameQ[Exp[a], Exp[Expand[a]]],

myDTFT[ Cos[a_] x_., n_, w_, z_, options_, flag_ ] :>
	myDTFT[ Cos[Expand[a]] x, n, w, options, flag ] /;
	! SameQ[Cos[a], Cos[Expand[a]]],

myDTFT[ Sin[a_] x_., n_, w_, z_, options_, flag_ ] :>
	myDTFT[ Sin[Expand[a]] x, n, w, options, flag ] /;
	! SameQ[Sin[a], Sin[Expand[a]]],

(*	2.  Expand out products like (n + 1)(n + 2) ...	*)
myDTFT[ x_, n_, w_, z_, options_, flag_ ] :>
	myDTFT[ Distribute[x], n, w, z, options, flag ] /;
	SameQ[Head[x], Times] && ! SameQ[x, Distribute[x]],

(*	3.  Use the z-transform	*)
myDTFT[ x_, n_, w_, z_, options_, True ] :> 
	Block [	{myz, nullstate, ztrans},
		nullstate = nullDTFTstate[];
		myz = SignalProcessing`Digital`ZTransform`Private`MyZByPass;
		ztrans = myz[ x, n, z, nList, zList,
			      {Dialogue -> False} ~Join~ options ];
		If [ InformUserQ[options],
		     Print[ "( after taking the z-transform of" ];
		     Print[ "  ", x ];
		     Print[ "  which yields" ];
		     Print[ "  ", ztrans ];
		     Print[ "  and adjusting the result )" ] ];
		If [ SameQ[Head[ztrans], ZTransData],
		     ( TheFunction[ztrans] /. z -> Exp[I w] ),
		     myDTFT[ MapAll[ ZtoDTFT[#1, n, w, z, options, nullstate]&,
				     ztrans ],
			     n, w, z, options, nullstate ] ] ]

}

(*  E N D     R U L E     B A S E  *)

(*  E N D     F O R W A R D     D T F T  *)


(*  B E G I N     I N V E R S E     D T F T  *)

InvDTFTransform::noncont =
	"Discrete operators and functions were converted into continuous ones."

(*  Conversion from operator notation to function notation  *)
Unprotect[InvDTFT]
InvDTFT/: TheFunction [ InvDTFT[w_, n_][f_] ] := InvDTFTransform[f, w, n]
Protect[InvDTFT]

(*  Give it options  *)
InvDTFTransform/: Options[InvDTFTransform] :=
	displayFixUp[ invFixUp,
		      Join[ { Definition -> False,
			      Dialogue -> False,
			      Terms -> False },
			    Options[InvZTransform] ] ]

(*  Input a function and test to see if needs to be sent to the    *)
(*  multidimensional or one-dimensional inverse Fourier transform. *)
InvDTFTransform[ DTFTData[ trans_, FVariables[vars_] ] ] :=
	InvDTFTransform [ trans, vars ]

InvDTFTransform[ f_ ] :=
	Message[ Transform::novariables, "w (frequency)", GetVariables[f] ]

InvDTFTransform[ f_, w_ ] :=
	InvDTFTransform[ f, w, DummyVariables[Length[w], Global`n] ]

InvDTFTransform[ f_, w_, n_, options___ ] :=
	Message[ Transform::badvar, "continuous-frequency",
		 InvDTFTransform, w ] /;
	! validvarQ[w]

InvDTFTransform[ f_, w_, n_, options___ ] :=
	Message[ Transform::badvar, "discrete-time", InvDTFTransform, n ] /;
	! validvarQ[n]

InvDTFTransform[ f_, varin_, varout_, options___ ] :=
	Block [	{freqfun, invfun, op, vars, z, zvars},
		vars = If [ Length[varin] != Length[varout],
			    DummyVariables[Length[varin], Global`n],
			    varout ];

		zvars = DummyVariables[Length[varin], z];

		freqfun = ToContinuous[f];
		If [ ! SameQ[freqfun, f],
		     Message[InvDTFTransform::noncont] ];

		wList = ToList[varin];
		nList = ToList[vars];
		zList = ToList[zvars];

		op = ToList[options] ~Join~ Options[InvDTFTransform];
		multidFlag = ( Length[varin] > 1 );
		invfun = If [ multidFlag, 
			      multiDInvDTFT[freqfun, varin, vars, zvars, op],
			      MyInvDTFT[freqfun, varin, vars, zvars, op] ];

		If [ InformUserQ[op],
		     Scan[invexplain, invfun, Infinity] ];

		invfun ]

(*  Multidimensional inverse discrete-time Fourier transform  *)
multiDInvDTFT[ f_, wl_, nl_, zl_, oplist_ ] :=
	Block [	{fun = f, i, len, newop},
		len = Length[wl];
		newop = MultiDLookup[oplist, wl, nl];
		For [ i = 1, i <= len, i++,
		      fun = MyInvDTFT[fun, wl[[i]], nl[[i]], zl[[i]], newop] ];
		fun ]				

(*  One-dimensional inverse discrete-time Fourier transform  *)
MyInvDTFT[ f_, w_, n_, z_, op_ ] :=
	Block [ {newexpr = myinvDTFT[f, w, n, z, invFixUp[op], {True, True}],
		 newinvdtftrules, oldexpr = Null, trace},

		(* generate the inverse DTFT rules *)
		newinvdtftrules = TransformFixUp[ w, n, op, myinvDTFT, False,
						  InvDTFTransform, Null, Null ];
		InvDTFTRules = Join[ newinvdtftrules, OriginalInvDTFTRules ];

		(* determine the level of dialogue *)
		trace = SameQ[ Replace[Dialogue, op], All ];

		(* take the 1-D inverse DTFT *)
		While [ ! SameQ[newexpr, oldexpr], 
			If [ trace, Print[newexpr]; Print[ "which becomes" ] ];
			oldexpr = newexpr;
			newexpr = oldexpr /. ( myinvDTFT[a__] :>
				    Replace[ myinvDTFT[a], InvDTFTRules ] ) ];
		If [ trace, Print[newexpr] ];

		(* fix up the result *)
		newexpr = postinvtransform[oldexpr];
		While [ ! SameQ[newexpr, oldexpr], 
			If [ trace, Print[newexpr]; Print[ "which becomes" ] ];
			oldexpr = newexpr;
			newexpr = postinvtransform[oldexpr] ];

		(* simplify expression if requested *)
		If [ Replace[Simplify, op],
		     newexpr = SPSimplify[newexpr,
					  Dialogue -> trace,
					  Variables -> nList] ];

		newexpr ]


(*  Supporting Routines  *)

breakItUp[ a_. f_, w_, k_ ] := { a, f } /;
	FreeQ[a, k] && ! FreeQ[f, k]

checkFactoring[ a_, w_, k_ ] := breakItUp[ Factor[a], w, k ]

checkFactoringQ[ a_, w_, k_ ] :=
	! SameQ[ First[ checkFactoring[ a, w, k ] ], 1 ]

candidateList = {}
periodicX = {}
nonPeriodicX = {}

downShiftPair[x_, y_, m_] := 
	Block [	{diff, ratio},
		diff = x - y;
		If [ Apply[SameQ, diff],
		     ratio = First[diff] / (2 Pi);
		     IntegerQ[ratio] && ( -m <= ratio <= m ) ] ] /;
	Length[x] == Length[y]

downsampled1DcheckQ[ x_Plus, w_, m_ ] :=
	Block [	{i, j, length, lengthList, newx, rule},
		newx = MyCollectAll[x, w];
		periodicX = {};
		rule = a_. Periodic[2 Pi m, w][f_] :>
			   Block [ {}, AppendTo[periodicX, a f]; 0 ];
		nonPeriodicX = Map[ Replace[#, rule]&, newx ];

		(*  Determine which functions are shifted versions of  *)
		(*  one another--- first compute all shift factors for *)
		(*  each candidate and then compare them pairwise      *)
		shiftFactors =
			Expand[ Map[ GetAllShiftFactors[#, w]&, periodicX ] ];
		length = Length[ shiftFactors ];
		lengthList = Map[ Length, shiftFactors ];
		For [ i = 1, i <= length, i++,
		      candidateList = {i};
		      For [ j = 1, j <= length, j++,
			    If [ (i != j) &&
				   downShiftPair[ shiftFactors[[i]],
						  shiftFactors[[j]], m ],
				 AppendTo[candidateList, j] ] ];
		      If [ SameQ[Length[candidateList], m], Break[] ] ];
		SameQ[ Length[candidateList], m ] ]

invexplain[ myinvDTFT[ x_, w_, rest__ ] ] :=
	Message[ Transform::incomplete,
		 "inverse discrete-time Fourier transform", x, w ]

(*  invFixUp --  removes redundancy and TransformLookup in options list  *)
invFixUp[ op_ ] := { Definition -> Replace[Definition, op],
		     Dialogue -> Replace[Dialogue, op],
		     Terms -> Replace[Terms, op] }

(*  invertDownsampledDTFT  *)
invertDownsampledDTFT[ x_, w_, n_, z_, options_, flag_, m_ ] :=
	Block [ {},
		If [ ! IntegerQ[m],
                     If [ SameQ[ Replace[Dialogue, options], All ],
		          Print[ "assuming ", m, " is an integer" ] ] ];
		Abs[m] Downsample[m, n][
			 myinvDTFT[x /. w -> m w, w, n, z, options, flag] ] ] /;
	Implies[ NumberQ[m], IntegerQ[m] ]

(*  invertResampledDTFT  *)
invertResampledDTFT[ x_, w_, n_, z_, options_, flag_, y_, f_ ] :=
	invertResampledDTFT[ x, w, n, z, options, flag,
			     y, Numerator[f], Denominator[f] ]

invertResampledDTFT[ x_, w_, n_, z_, options_, flag_, y_, m_, l_ ] :=
	Block [	{extraterms = 0, newx, upfact},
		upfact = If [ SameQ[m, 2], l, 2 l ];
		If [ IntegerQ[upfact] && upfact < 0, upfact = -upfact ];
		If [ ! IntegerQ[upfact],
                     If [ SameQ[ Replace[Dialogue, options], All ],
		          Print[ "assuming ", upfact, " is an integer" ] ] ];
		newx = x /. w -> (w/upfact);
		If [ SameQ[y, 0],
		     extraterms = myinvDTFT[y, w, n, z, options, flag] ];
		extraterms +
		Upsample[upfact, n][
			myinvDTFT[newx, w, n, z, options, flag] ] ] /;
	( SameQ[m, 2] || SameQ[m, 1] ) && FreeQ[l, w] && (! SameQ[l, 1]) &&
	  Implies[ NumberQ[l], IntegerQ[l] ]

invertResampledDTFT[ x_, w_, n_, z_, options_, flag_, y_, m_Integer, 1 ] :=
	Block [	{extraterms},
		extraterms = nonPeriodicX;
		If [ Length[candidateList] < m/2,
		     indices = Intersection[ Range[m/2], candidateList ];
		     extraterms += Apply[ Plus, periodicX[[indices]] ] ];
		thefun = periodicX[[ First[candidateList] ]];
		If [ ! SameQ[extraterms, 0],
		     extraterms =
			myinvDTFT[extraterms, w, n, z, options, flag] ];
		invertDownsampledDTFT[ thefun, w, n, z, options, flag, m/2 ] +
		  extraterms ] /;
	EvenQ[m] && ( m > 2 ) &&
	  downsampled1DcheckQ[ Periodic[m Pi, w][x] + y, w, m/2 ]

invertResampledDTFT[ x_, w_, n_, z_, options_, flag_, y_, m_Integer, 1 ] :=
	invertResampledDTFT[x, w, n, z, options, flag, y, 2 m, 2 ] /;
	OddQ[m]


postinvtransform[x_] := ReplaceRepeated[x, postinvrules]

postinvrules = {

	(*	4.  Apply the definition		*)
	myinvDTFT[ a_ Pulse[l_, w_ + s_.], w_, n_, z_, options_, flag_ ] :>
		TransformDialogue[ Definition, options, Integrate,
			a Pulse[l, w + s],
			Integrate[ a Exp[I w n], {w, -s, l - s}] / (2 Pi) ] /;
		Replace[Definition, options] && N[(Pi > s) && (Pi < l - s)],

	myinvDTFT[ x_, w_, n_, z_, options_, flag_ ] :>
		TransformDialogue[ Definition, options, Integrate, x,
			   Integrate[x Exp[I w n], {w, -Pi, Pi}] / (2 Pi) ] /;
		Replace[Definition, options],

	substituteforn[x_, n_Symbol, -n_] :>
		If [ Count[{x}, f_[p___][a___], Infinity] > 0,
		     Rev[n][posttransform[x]],          (* operators present *)
		     posttransform[x] /. n -> -n ] ,    (* no operators *)

	substituteforn[x_, n_, newn_] :> ( x /. n -> newn )
}

(* Routines to detect upsampling in the frequency response  *)

upsamplefactorQ[ f_ ] := (! SameQ[f, 0]) && (! SameQ[f, 1]) && (! SameQ[f, -1])
upsampledQ[ x_, w_ ] := upsamplefactorQ[ UpsampleFactor[x, w, GetAllFactors] ]

upsampledmDQ[ x_, w_ ] :=
	Block [	{cond},
		cond = ! MyFreeQ[ GetAllShiftFactors[x, w], wList ];
		If [ cond,
		     Needs[ "SignalProcessing`Digital`MDDTFT`" ];
		     cond = upsampleSystemQ[ x, wList ] ];
		cond ]


(*  Printed forms of supported routines for Dialogue -> All option  *)

Format[ myinvDTFT[ x_, w_, n_, z_, options_, flag_ ] ] :=
	SequenceForm[ ColumnForm[{"DTFT" Superscript[-1],
				  "     " ~StringJoin~ ToString[w]}],
		      { x } ]

Format[	substituteforn[x_, n_, newn_] ] :=
	SequenceForm[ {x}, Subscript[n -> newn] ]


(*  B E G I N     R U L E     B A S E  *)


InvDTFTRules = {}


OriginalInvDTFTRules = {


myinvDTFT[ Periodic[2 Pi, w_][x_], w_, n_, z_, options_, flag_ ] :>
	myinvDTFT[x, w, n, z, options, flag],


(*  A.	Lookup Rules		*)
(*	1.  Summation forms	*)
myinvDTFT[ Summation[k_,-Infinity,Infinity,1][a_. Delta[w_+w0_.+b_. Pi k_] +
					a_. Delta[w_ + A_. + c_. Pi k_] + x_.],
	   w_, n_, z_, options_, flag_ ] :>
	a Cos[A n] / Pi + Summation[k, -Infinity, Infinity, 1][x] /;
	( A == - w0 ) && ( SameQ[b, 2] || SameQ[b, -2] ) &&
	  ( SameQ[c, 2] || SameQ[c, -2] ) && FreeQ[{a, k, w0}, w],

myinvDTFT[ Summation[k_,-Infinity,Infinity,1][a_. Delta[w_+w0_.+b_. Pi k_] +
					  d_. Delta[w_+A_.+c_. Pi k_] + x_.],
	   w_, n_, z_, options_, flag_ ] :>
	(a I) Sin[A n] / Pi + Summation[k, -Infinity, Infinity, 1][x] /;
	( A == -w0 ) && ( a == -d ) && ( SameQ[b, 2] || SameQ[b, -2] ) &&
	  ( SameQ[c, 2] || SameQ[c, -2] ) && FreeQ[{a, A, w0}, w],

myinvDTFT[ Summation[k_, -Infinity, Infinity, 1][
					a_. Delta[w_+w0_.+b_. Pi k_] + x_.],
	   w_, n_, z_, options_, flag_ ] :>
	a Exp[- I w0 n] / (2 Pi) + Summation[k, -Infinity, Infinity, 1][x] /;
	( SameQ[b, 2] || SameQ[b, -2] ) && FreeQ[{a, k, w0}, w],

myinvDTFT[ Summation[k_,-Infinity,Infinity,1][a_. Delta[w_ + b_. Pi k_ / L_]],
		w_, n_, z_, options_, flag_ ] :>
	L/(2 Pi) Summation[k,-Infinity,Infinity,1][a Exp[I 2 Pi k n / (L+1)]] /;
	FreeQ[{a, k, L}, w] && ( SameQ[b, -2] || SameQ[b, 2] ),

(*	2.  Constant function	*)
myinvDTFT[ a_, w_, n_, z_, options_, flag_ ] :> a Impulse[n] /; FreeQ[a, w],

(*	3.  Pulse in continuous frequency	*)
myinvDTFT[ CPulse[L_, a_. w_ + w1_.], w_, n_, z_, options_, flag_ ] :>
	L/a Exp[I w1 n / a] Exp[- I L n / (2 a)] Sinc[L n / (2 a)] / (2 Pi) /;
	FreeQ[{a, L, w1}, w],

myinvDTFT[ A_. CStep[w_ + w0_.] - A_. CStep[w_ + w1_.] + x_.,
	   w_, n_, z_, options_, flag_ ] :>
	myinvDTFT[ A CPulse[w0 - w1, w + w0], w, n, z, options, flag ] +
	  myinvDTFT[ x, w, n, z, options, flag ] /;
	FreeQ[{w0, w1}, w],

(*	4.  Step function	*)
myinvDTFT[ 1 / ( 1 - Exp[- I w_] ) +
	   p1_. Summation[k_,-Infinity,Infinity,1][p2_. Delta[w_ + b_. Pi k_]],
	   w_, n_, z_, options_, flag_] :> 
	Step[n] /;
	FreeQ[k, w] && SameQ[p1 p2, Pi] && ( SameQ[b, 2] || SameQ[b, -2] ),

(* 	5.  Dirichlet kernel (aliased sinc)	*)
myinvDTFT[ Dirichlet[L_, w_ + w0_.], w_, n_, z_, options_, flag_ ] :>
	Exp[- I w0 n] Pulse[L, n + (L - 1)/2] /;
	FreeQ[{L, w0}, w],

(*	6.  Differentiator (high pass) filter	*)
myinvDTFT[ w_ CPulse[2 Pi, w_ + Pi], w_, n_, z_, options_, flag_ ] :>
	-2 I Pi (-1)^n / n,


(*  B.	Properties				*)
(*      1.  Resampling---  all Periodic[2 Pi, w] operators have already  *)
(*			   been processed by the rule base.		 *)
myinvDTFT[ Summation[k_, 0, Lminus1_, 1][ Periodic[m_. Pi, w_][ x_ ] ],
	   w_, n_, z_, options_, flag_ ] :>
	invertDownsampledDTFT[ x /. k -> 0, w, n, z, options, flag, m/2 ] /;
	( SameQ[m/2, Lminus1 + 1] || SameQ[Abs[m/2], Lminus1 + 1] ) &&
	( Count[ x, w/(m/2) + 2 Pi k/(m/2) + h_., Infinity ] > 0 ||
	  Count[ x, (w + 2 Pi k + h_.)/(m/2), Infinity ] > 0 ),

myinvDTFT[ Periodic[m_. Pi, w_][ x_ ] + y_., w_, n_, z_, options_, flag_ ] :>
	invertResampledDTFT[ x, w, n, z, options, flag, y, Rationalize[m] ],

(*	2.  Multiplication by a constant	*)
myinvDTFT[ a_ x_, w_, n_, z_, options_, flag_ ] :>
	a myinvDTFT[x, w, n, z, options, flag] /;
	FreeQ[a, w],

(*	3.  Additivity				*)
myinvDTFT[ a_ + b_, w_, n_, z_, options_, flag_ ] :>
	myinvDTFT[a, w, n, z, options, flag] +
	myinvDTFT[b, w, n, z, options, flag],

(*	4.  Multiplication by a complex exp.	*)
myinvDTFT[ Exp[Complex[0, n1_] n0_. w_ + b_.] x_.,
	   w_, n_, z_, options_, flag_ ] :>
	Exp[b] substituteforn[ myinvDTFT[x, w, n, z, options, flag],
			       n, n + n0 n1 ] /;
	FreeQ[{b, n0, n1}, w],

(*	4.  Summation				*)
myinvDTFT[ x_. / ( 1 - Exp[- I w_] ) +
	   Pi Summation[k_,-Infinity,Infinity,1][Delta[w_ + b_. Pi k_]],
	   w_, n_, z_, options_, flag_ ] :>
	Summation[k, -Infinity, Infinity, 1][
	  myinvDTFT[x, w, n, z, options, flag] ] /;
	FreeQ[k, w] && ( SameQ[b, -2] || SameQ[b, 2] ),

myinvDTFT[ b_. Summation[k_,-Infinity,Infinity,1][a_],
	   w_, n_, z_, options_, flag_ ] :>
	Block [	{f, newdtft, rest},
		{f, rest} = checkFactoring[a, w, k];
		newdtft = b f Summation[k,-Infinity,Infinity,1][Expand[rest]];
		myinvDTFT[ newdtft, w, n, z, options, flag ] ] /;
	checkFactoringQ[a, w, k],

(*	5.  Multdimensional upsampling	*)
myinvDTFT[ x_, w_, n_, z_, options_, flag_ ] :>
	undoUpsampling[ x, w, n, z, options, flag ] /;
	multidFlag && upsampledmDQ[ x, w ],

(*      6.  An operator independent of w---  take transform of f    *)
myinvDTFT[ operator_[params__][f_], w_, n_, z_, options_, flag_ ] :>
	operator[params][ myinvDTFT[f, w, n, z, options, flag] ] /;
	FreeQ[{params}, w],


(*  C.	Strategies					*)
(*	1.  Collect all subexpressions in terms of w	*)
myinvDTFT[ x_, w_, n_, z_, options_, {True, flag2_} ] :>
	myinvDTFT[ MyCollectAll[x, w], w, n, z, options, { False, flag2 } ],

(*	2.  Expand out products like (w + 1)(w + 2) ...	*)
myinvDTFT[ x_, w_, n_, z_, options_, flag_ ] :>
	myDTFT[ Distribute[x], n, w, z, options, flag ] /;
	SameQ[Head[x], Times] && ! SameQ[x, Distribute[x]],

(*	3.  Take inverse z-transform			*)
myinvDTFT[ x_, w_, n_, z_, options_, {flag1_, True} ] :>
	Block [	{myinvz, newx, invztrans},
		newx = SPSimplify[ ( x /. w -> ( - I Log[z] ) ) ];
		myinvz =
		  SignalProcessing`Digital`InvZTransform`Private`MyInvZByPass;
		invztrans = myinvz[ newx, z, n, zList, nList,
				    {Dialogue -> False} ~Join~ options ];
		If [ InformUserQ[options],
		     Print[ "( after taking the inverse z-transform of" ];
		     Print[ "  ", x ];
		     Print[ "  which yields" ];
		     Print[ "  ", invztrans ];
		     Print[ "  and adjusting the result )" ] ];
		If [ InvalidInvZTransformQ[invztrans],
		     myinvDTFT[ invztrans, w, n, z, options, {flag1, False} ],
		     invztrans ] ],

(*	    Clean up expression returned from inverse z-transform	*)
myinvDTFT[SignalProcessing`Digital`InvZTransform`Private`myinvz[x_, z_, rest__], w_, n_, z_, options_, flag_ ] :>
	Block [	{dtftform},
		dtftform = SPSimplify[ ( x /. z -> Exp[I w] ) ];
		myinvDTFT[dtftform, w, n, z, options, flag] ]

}


(*  E N D     R U L E     B A S E  *)

(*  E N D     I N V E R S E     D T F T  *)


(*  E N D     P A C K A G E  *)

End[]
EndPackage[]

If [ TrueQ[ $VersionNumber >= 2.0 ],
     On[ General::spell ];
     On[ General::spell1 ] ];


(*  H E L P     I N F O R M A T I O N  *)

Combine [ SPfunctions, { DTFTransform, InvDTFTransform } ]
Protect [ DTFTransform, InvDTFTransform ]


(*  E N D I N G     M E S S A G E  *)

Print["The discrete-time Fourier transform (DTFT) rule bases are loaded."]
Null
